#include "parse.h"
#include "externs.h"
#include "init.h"
#include "execute.h"
#include "builtin.h"

void get_command (int i);
void getname (char *name);
void print_command ();

/**
 * shell主循环
 */
void shell_loop (void) {
    while (1) {
        /* 初始化环境 */
        init ();
        /* 读取命令 */
        if (-1 == read_command ()) {
            break;
        }
        /* 解析命令 */
        parse_command ();
        // /* 打印命令状态 */
        // print_command ();
        /* 执行命令 */
        execute_command ();
    }
    printf ("\nExit\n");
}

/**
 * 读取命令
 * return: success 0;failed/EOF -1.
 */
int read_command (void) {
    /* 按行读取命令，cmdline中包含\n字符 */
    // 按下ctrl+d输入结束符使fgets()返回NULL跳出循环
    if (NULL == fgets (cmdline, MAXLINE, stdin)) {
        return -1;
    }
    return 0;
}

/**
 * 解析命令
 * return: success - count of commands parsed;
 *         failed - -1.
 */
int parse_command (void) {
    /* 若一开始就检测到'\n'就直接返回 */
    if (check ("\n")) {
        return 0;
    }

    /* 先判定是否内部命令并执行它 */
    if (builtin ()){
        return 0;
    }

    /* cat < test.txt | grep -n public > test2.txt */
    /* 1.解析第一条简单命令 */
    get_command (0);
    /* 2.判定是否有输入重定向符 */
    if (check ("<")) {
        getname (infile);
    }
    /* 3.判定是否有管道 */
    int i;
    for (i = 1; i < PIPELINE; ++i) {
        if (check ("|")) {
            get_command (i);
        } else {
            break;
        }
    }
    /* 4.判定是否有输出重定向符 */
    if (check (">")) {
        /* 检测是否为追加模式">>" */
        if (check (">")) {
            append = 1;
        }
        getname (outfile);
    }
    /* 5.判定是否有后台作业 */
    if (check ("&")) {
        backgrnd = 1;
    }
    /* 6.判定命令结束'\n' */
    if (check ("\n")) {
        cmd_count = i;
        return cmd_count;
    } else {
        fprintf (stderr, "Command line syntax error\n");
        return -1;
    }
    return 0;
}

/**
 * 执行命令
 * return: success - 0;
 *         failed - -1.
 */
int execute_command (void) {

    execute_disk_command ();
    return 0;
}

void print_command()
{
    int i, j;
    if (cmd_count) {
        printf ("cmd_count = %d\n", cmd_count);
        for (i = 0; i < cmd_count; ++i) {
            j = 0;
            while (NULL != cmd[i].args[j]) {
                printf ("[%s] ", cmd[i].args[j]);
                ++j;
            }
            printf ("\n");
        }
        printf ("backgrnd = %d\n", backgrnd);
        printf ("append = %d\n", append);
        printf ("lastpid = %d\n", lastpid);
        if ('\0' != infile[0]) {
            printf ("infile = [%s]\n", infile);
        }
        if ('\0' != outfile[0]) {
            printf ("outfile = [%s]\n", outfile);
        }
    }
}

/**
 * 解析简单命令至cmd[i]
 * 提取cmdline中的命令参数到avline数组中
 * 并将COMMAND结构中的args[]的每个指针指向这些字符串
 */
void get_command (int i) {
    /* cat < test.txt | grep -n public > test2.txt */
    int j = 0;
    int inword = 0;
    while ('\0' != *lineptr) {
        /* 去空格 */
        while (' ' == *lineptr || '\t' == *lineptr) {
            lineptr++;
        }

        /* 将第i条命令第j个参数指向avptr */
        cmd[i].args[j] = avptr;
        /* 提取参数 */
        while ('\0' != *lineptr &&
                ' ' != *lineptr &&
                '\t' != *lineptr &&
                '\n' != *lineptr &&
                '<' != *lineptr &&
                '|' != *lineptr &&
                '>' != *lineptr &&
                '&' != *lineptr) {
            /* 参数提取至avptr指针所指向的数组avline */
            *avptr++ = *lineptr++;
            inword = 1;
        }
        *avptr++ = '\0';
        switch (*lineptr)
        {
        case ' ':
        case '\t':
            inword = 0;
            j++;
            break;
        case '<':
        case '|':
        case '>':
        case '&':
        case '\n':
            if (0 == inword) {
                cmd[i].args[j] = NULL;
            }
            return;
        case '\0':
        default:
            return;
        }
    }
}

/**
 * 将lineptr中的字符串与str进行匹配
 * 若匹配成功lineptr将会移过所匹配的字符串
 * 失败则保持不变
 * return: success - 1;
 *         failed - 0.
 */
int check (const char *str) {
    char *p;
    /* 去空格 */
    while (' ' == *lineptr || '\t' == *lineptr) {
        lineptr++;
    }
    p = lineptr;
    while ('\0' != *str && *p == *str) {
        str++;
        p++;
    }

    if ('\0' == *str) {
        lineptr = p;  /* lineptr移过所匹配的字符串 */
        return TRUE;
    }

    /* lineptr保持不变 */
    return FALSE;
}

void getname (char *name) {
    /* 去空格 */
    while (' ' == *lineptr || '\t' == *lineptr) {
        lineptr++;
    }
    /* 提取文件名 */
    while ('\0' != *lineptr &&
            ' ' != *lineptr &&
            '\t' != *lineptr &&
            '\n' != *lineptr &&
            '<' != *lineptr &&
            '|' != *lineptr &&
            '>' != *lineptr &&
            '&' != *lineptr) {
        *name++ = *lineptr++;
    }
    *name = '\0';
}
